import { useMemo, useRef } from 'react';
import { Rnd, Props as RndProps } from 'react-rnd';
import clsx from 'clsx';
import Tooltip from '@mui/material/Tooltip';
import IconButton from '@mui/material/IconButton';
import FormatBoldOutlinedIcon from '@mui/icons-material/FormatBoldOutlined';
import CloseOutlinedIcon from '@mui/icons-material/CloseOutlined';
import CodeOutlinedIcon from '@mui/icons-material/CodeOutlined';
import FormatItalicOutlinedIcon from '@mui/icons-material/FormatItalicOutlined';
import LinkOutlinedIcon from '@mui/icons-material/LinkOutlined';
import StrikethroughSOutlinedIcon from '@mui/icons-material/StrikethroughSOutlined';
import FormatUnderlinedOutlinedIcon from '@mui/icons-material/FormatUnderlinedOutlined';
import PaletteOutlinedIcon from '@mui/icons-material/PaletteOutlined';
import EditLocationAltIcon from '@mui/icons-material/EditLocationAlt';
import CircularProgress from '@mui/material/CircularProgress';
import { useEditor, EditorContent, BubbleMenu } from '@tiptap/react';
import Placeholder from '@tiptap/extension-placeholder';
import { Color } from '@tiptap/extension-color';
import Document from '@tiptap/extension-document';
import Paragraph from '@tiptap/extension-paragraph';
import Bold from '@tiptap/extension-bold';
import Text from '@tiptap/extension-text';
import Underline from '@tiptap/extension-underline';
import Italic from '@tiptap/extension-italic';
import Strike from '@tiptap/extension-strike';
import Code from '@tiptap/extension-code';
import Blockquote from '@tiptap/extension-blockquote';
import Link from '@tiptap/extension-link';
import Highlight from '@tiptap/extension-highlight';
import TextStyle from '@tiptap/extension-text-style';
import History from '@tiptap/extension-history';
import { formatPoi } from '@/api';
import { useControlledState, useMapEventListener, useApiPoiSearch } from '@/hooks';
import { HighlighterIcon } from '../icons';
import { ColorfulPopover } from '../colorful';
import { ContentAI, Material } from './extensions';
import { register } from './extensions/material/suggestion';
import type { ISMap } from '../map-kit';
import './note-editor.less';

export type NoteEditorProps = {
  open?: boolean;
  onCancel?: () => void;
  onOpenChange?: (open?: boolean) => void;
  map: ISMap;
};

type ICtrlRecord = {
  key: string;
  content: string;
  desc?: string;
  icon: React.ReactNode;
  isActive: boolean;
  onClick: () => void;
  render?: (node: React.ReactNode) => React.ReactNode;
};

type INoteLocationProps = {
  map: ISMap;
  update?: boolean;
};
const prefixCls = 'smap-note-editor';
const enableDrag = 'enable-drag';
const content = '';
const minHeight = 600;
const minWidth = 500;

const NoteLocation = (props: INoteLocationProps) => {
  const { map, update } = props;
  const { run, result, status } = useApiPoiSearch();
  useMemo(() => update && run(map.getCenter()), [update]);

  const render = () => {
    switch (status) {
      case 'loading':
        return <CircularProgress size={16} />;
      case 'loaded': {
        const poi = formatPoi(result?.result);
        return (
          <>
            <EditLocationAltIcon sx={{ color: '#43C494', fontSize: 16 }} />
            <div className="note-address">笔记位置：{poi.address}</div>
          </>
        );
      }
      case 'error':
        return <div className="location-error">获取位置信息失败</div>;
    }
  };
  return <div className="smap-note-location">{render()}</div>;
};

export const NoteEditor = (props: NoteEditorProps) => {
  const { open: propOpen, onOpenChange, onCancel: propOnCancel, map } = props;
  const extensions = useMemo(
    () => [
      Document,
      Paragraph,
      Text,
      TextStyle,
      Color,
      Bold,
      Italic,
      Underline,
      Strike,
      Code,
      Blockquote,
      Link.configure({ openOnClick: false, autolink: true }),
      Highlight.configure({ multicolor: true }),
      History,
      Placeholder.configure({ placeholder: '写一些东西，或者按“空格”键唤起AI，输入“/”命令...' }),
      Material.configure({ suggestion: register({ componentProps: { map } }) }),
    ],
    [],
  );

  const editor = useEditor({ extensions, content });
  const [open, setVisible] = useControlledState(propOpen, onOpenChange);
  const rndRef = useRef<Rnd>(null);
  const rndPropsRef = useRef<RndProps>({
    ref: rndRef,
    className: prefixCls,
    dragHandleClassName: enableDrag,
    minHeight,
    minWidth,
    default: {
      x: 90,
      y: 5,
      width: minWidth,
      height: 'calc(100vh - 20px)',
    },
  });

  const onCancel = () => {
    setVisible(false);
    propOnCancel?.();
  };

  const setLink = () => {
    if (!editor) return;
    const previousUrl = editor.getAttributes('link').href;
    const url = window.prompt('URL', previousUrl);
    if (url === null) return;
    if (url === '') {
      editor.chain().focus().extendMarkRange('link').unsetLink().run();
      return;
    }
    editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();
  };

  const onHighlighterClick = () => {
    if (!editor) return;
  };

  const getEditorCtrls = () => {
    if (!editor) return [];
    const editorCtrlList: ICtrlRecord[] = [
      {
        key: 'bold',
        content: '加粗',
        icon: <FormatBoldOutlinedIcon />,
        onClick: () => editor.chain().focus().toggleBold().run(),
        isActive: editor.isActive('bold'),
      },
      {
        key: 'underline',
        content: '下划线',
        icon: <FormatUnderlinedOutlinedIcon />,
        onClick: () => editor.chain().focus().toggleUnderline().run(),
        isActive: editor.isActive('underline'),
      },
      {
        key: 'italic',
        content: '斜体',
        icon: <FormatItalicOutlinedIcon />,
        onClick: () => editor.chain().focus().toggleItalic().run(),
        isActive: editor.isActive('italic'),
      },
      {
        key: 'strike',
        content: '删除线',
        icon: <StrikethroughSOutlinedIcon />,
        onClick: () => editor.chain().focus().toggleStrike().run(),
        isActive: editor.isActive('strike'),
      },
      {
        key: 'code',
        content: '代码',
        icon: <CodeOutlinedIcon rotate={90} />,
        onClick: () => editor.chain().focus().toggleCode().run(),
        isActive: editor.isActive('code'),
      },
      {
        key: 'blockquote',
        content: '代码块',
        icon: <CodeOutlinedIcon />,
        onClick: () => editor.chain().focus().toggleBlockquote().run(),
        isActive: editor.isActive('blockquote'),
      },
      { key: 'link', content: '链接', icon: <LinkOutlinedIcon />, onClick: setLink, isActive: editor.isActive('link') },
      {
        key: 'highlight',
        content: '高亮',
        icon: <HighlighterIcon />,
        isActive: editor.isActive('highlight'),
        onClick: onHighlighterClick,
        // onClick: () => editor.chain().focus().toggleHighlight().run(),
        render: (node) => (
          <ColorfulPopover showContentWrap key="highlight">
            {node}
          </ColorfulPopover>
        ),
      },
      {
        key: 'color',
        content: '颜色',
        icon: <PaletteOutlinedIcon />,
        isActive: editor.isActive('textStyle', { color: '#958DF1' }),
        onClick: () => editor.chain().focus().setColor('#958DF1').run(),
        render: (node) => (
          <ColorfulPopover showContentWrap key="color">
            {node}
          </ColorfulPopover>
        ),
      },
    ];
    return editorCtrlList;
  };

  useMapEventListener(map, 'markerFeature.create', () => {});

  if (!open || !editor) return null;
  return (
    <Rnd {...rndPropsRef.current}>
      <div className={`${prefixCls}-header`}>
        <div className={enableDrag}>
          <NoteLocation map={map} update={open} />
        </div>
        <IconButton onClick={onCancel}>
          <CloseOutlinedIcon />
        </IconButton>
      </div>
      <div className={`${prefixCls}-body`}>
        <EditorContent editor={editor} className="smap-tiptap" />
        <BubbleMenu className="smap-bubble-menu" editor={editor} tippyOptions={{ duration: 100, maxWidth: 'max-content' }}>
          <div className="editor-ctrl">
            {getEditorCtrls().map(({ key, icon, onClick, isActive, content }) => (
              <Tooltip arrow title={content} key={key}>
                <IconButton className={clsx({ active: isActive })} onClick={onClick}>
                  {icon}
                </IconButton>
              </Tooltip>
            ))}
          </div>
        </BubbleMenu>
        <ContentAI editor={editor} />
      </div>
    </Rnd>
  );
};
